package com.laviedesfons.jhmtasc.cadmium;

import com.laviedesfons.jhmtasc.exceptions.MException;
import com.laviedesfons.jhmtasc.exceptions.MRuntimeException;
import com.laviedesfons.jhmtasc.logging.CustomLevel;
import com.laviedesfons.jhmtasc.logging.CustomLogger;
import com.laviedesfons.jhmtasc.metadata.TypeUtils;
import com.laviedesfons.jhmtasc.types.abstracts.Interface;
import com.laviedesfons.jhmtasc.types.externals.JBool;
import com.laviedesfons.jhmtasc.types.externals.JInt;
import com.laviedesfons.jhmtasc.types.externals.JString;
import com.laviedesfons.jhmtasc.types.interfaces.InternalType;
import com.laviedesfons.jhmtasc.types.internals.PBool;
import com.laviedesfons.jhmtasc.types.internals.PInt;
import com.laviedesfons.jhmtasc.types.internals.PList;
import com.laviedesfons.jhmtasc.types.internals.PString;
import com.laviedesfons.jhmtasc.types.models.Action;
import com.laviedesfons.jhmtasc.types.models.PushItem;
import fr.x9c.cadmium.kernel.Fail.Exception;
import fr.x9c.cadmium.kernel.*;
import java.util.logging.Logger;
import org.junit.Assert;

/**
 *
 * @author Romano
 */
@PrimitiveProvider
public class MTestPrimitiveProvider {

    protected static final Logger logger = CustomLogger.getLogger();

    public static InternalType root(Value v){
        try {
            return (InternalType) TypeUtils.getTypeUtils().createRootType().fromValue(v);
        } catch (MException ex) {
            throw new MRuntimeException(ex);
        }
    }


    private static void assertFail(String msg) {
        Assert.fail(msg);
    }

    private static Value assertEquals(Object o, Object expected) {
        if (!expected.equals(o)) {
            String msg = expected + " != " + o;
            assertFail((!"".equals(msg) ? " - " + msg : "")
                    + " Object :" + o.toString()
                    + " was expected to be " + expected.toString());
        }
        return Value.UNIT;
    }

    @Primitive
    public static Value echo(final CodeRunner ctxt, Value message) {
        logger.log(CustomLevel.TEST,message.asBlock().asString());
        return Value.UNIT;
    }

    @Primitive
    public static Value mocker(
            final CodeRunner ctxt, Value type, Value values) throws Exception {

        String aType;
        if ((aType = type.asBlock().asString()) != null) {
            if (aType.equals("IndexOutOfBoundException")) {
                Fail.arrayBoundError();
            } else if (aType.equals("NotFoundException")) {
                Fail.raiseNotFound();
            } else {
                return root(values).toValue();
            }
        }
        return Value.UNIT;
    }

    @Primitive
    public static Value fail(final CodeRunner ctxt, Value message) {
        assertFail(message.asBlock().asString());
        return Value.UNIT;
    }

    @Primitive
    public static Value assertInt(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                new PInt().fromValue(v),
                new PInt().fromValue(exp));
    }

    @Primitive
    public static Value assertBool(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                new PBool().fromValue(v),
                new PBool().fromValue(exp));
    }

    @Primitive
    public static Value assertString(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                new PString().fromValue(v),
                new PString().fromValue(exp));
    }

    @Primitive
    public static Value assertJInt(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                ((JInt) root(v)).getWrapped(),
                new PInt().fromValue(exp));
    }

    @Primitive
    public static Value assertJBool(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                ((JBool) root(v)).getWrapped(),
                new PBool().fromValue(exp));
    }

    @Primitive
    public static Value assertJString(
            final CodeRunner ctxt, Value v, Value exp) {

        return assertEquals(
                ((JString) root(v)).getWrapped(),
                new PString().fromValue(exp));
    }

    @Primitive
    public static Value assertActionType(
            final CodeRunner ctxt, Value v, Value expected) {

        return assertEquals(
                ((Action) root(v)).getFlag(),
                expected.asBlock().asString());
    }

    @Primitive
    public static Value assertActionItemType(
            final CodeRunner ctxt, Value v, Value expected) {

        PList<PushItem> items = (PList<PushItem>)((Action)root(v)).getWrapped();
        return assertEquals(
                ((PushItem) items.values().get(0)).getFlag(),
                expected.asBlock().asString());
    }

    @Primitive
    public static Value assertTagId(
            final CodeRunner ctxt, Value expected, Value v) {

        String flag;
        Interface root;
        try{
            root = TypeUtils.getTypeUtils().createRootType();
            root.fromValue(v);
            flag = root.getFlag();
        } catch (MException ex) {
            throw new AssertionError(ex);
        }
        assertEquals(flag, expected.asBlock().asString());
        return Value.UNIT;
    }
}